package com.xneure.utils.bean;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class BeanProcessor{
	static Map<Class<?>,Map<String,ClassProperty>> fields = new HashMap<>();
	static Map<Class<?>,Map<String,String>> methods = new HashMap<>();
	private Object obj;
	private Class<?> cls;

	public BeanProcessor(Class<?> cls){
		loadBean(cls);
		this.cls = cls;
	}

	public BeanProcessor(Object obj){
		this(obj.getClass());
		this.obj = obj;
	}

	public void setBean(Object obj){
		this.obj = obj;
	}

	private void loadBean(Class<?> cls){
		if(null != cls && Object.class.equals(cls) == false && fields.containsKey(cls) == false){
			synchronized(cls){
				Map<String,ClassProperty> fs = new LinkedHashMap<>();
				Map<String,String> ms = new LinkedHashMap<>();
				do{
					fields.put(cls,fs);
					methods.put(cls,ms);
					loadMethod(cls,ms);
					loadField(cls,fs);
				}while(Object.class.equals(cls = cls.getSuperclass()) == false);
			}
		}
	}

	protected void loadField(Class<?> cls,Map<String,ClassProperty> fs){
		for(Field f:cls.getDeclaredFields()){
			if(fs.containsKey(f.getName()) == false){
				if(processor(f)){
					fs.put(f.getName(),new ClassProperty(f,cls));
				}
			}
		}
	}

	protected void loadMethod(Class<?> cls,Map<String,String> fs){
		for(Method m:cls.getMethods()){
			String name = m.getName();
			if(fs.containsKey(name) == false){
				if(processor(m)){
					fs.put(name.toLowerCase(),name);
				}
			}
		}
	}

	protected boolean processor(Method m){
		return true;
	}

	protected boolean processor(Field field){
		return true;
	}

	public void setValue(String field,Object val){
		getField(cls,field).setValue(obj,val);
	}

	protected ClassProperty getField(Class<?> cls,String field){
		return getBeanInfo(cls).get(field);
	}

	public static Map<String,ClassProperty> getBeanInfo(Class<?> cls){
		if(fields.containsKey(cls) == false){
			new BeanProcessor(cls);
		}
		return fields.get(cls);
	}

	@SuppressWarnings("unchecked")
	public <T> T getValue(String field){
		return (T)getField(cls,field).getValue(obj);
	}

	public Field[] getFields(){
		Collection<ClassProperty> values = getBeanInfo(cls).values();
		Field[] fields = new Field[values.size()];
		int i = 0;
		for(ClassProperty item:values){
			fields[i++] = item.getField();
		}
		return fields;
	}
}
